The goal of this analysis is to assess the SMP population with CWL
monitoring data, categorize them and find the underrepresented smp
features in our data set. This is to ensure our monitoring effort
results in a more comprehensive data set that covers all types of SMPs
with varying design metrics such as loading ratios. The output of this
analysis can assist the data collection team with their future site
selection process.
#Libraries
library(odbc)
library(DBI)
library(lubridate)
library(tidyverse)
library(stats)
library(gridExtra)
library(grid)
library(gtable)
library(ggtext)
library(dplyr)
library(ggplot2)
library(knitr)
library(plotly)
library(cluster)
library(factoextra)
# DB PG14
con <- dbConnect(odbc::odbc(), dsn = "mars14_data", uid = Sys.getenv("shiny_uid"), pwd = Sys.getenv("shiny_pwd"), MaxLongVarcharSize = 8190)
#Getting list of SMPs
cwl_smp <- dbGetQuery(con,"SELECT DISTINCT smp_id
FROM fieldwork.viw_deployment_full_cwl")
#Getting the greenit info
smpbdv <- dbGetQuery(con,"SELECT * FROM external.tbl_smpbdv")
sysbdv <- dbGetQuery(con,"SELECT * FROM external.tbl_systembdv")
greenit_unified <-dbGetQuery(con,"SELECT * FROM external.viw_greenit_unified")
# join the greenit table with our smp list
smp_features <- cwl_smp %>%
inner_join(smpbdv, by="smp_id")
# Unmonitored SMPs
unmonitored_smp <- read.csv("C:\\Users\\Farshad.Ebrahimi\\OneDrive - City of Philadelphia\\Github Projects\\smp-population-assesment\\unmonitored_sites.csv") %>%
select(smp_id = SMP.ID) %>%
distinct()
# unmonitored smp_features
unmonitored_smp_features <- unmonitored_smp %>%
inner_join(smpbdv, by="smp_id")
The following code chunk calculates the break-down of SMP types with
CWL data.
#number of smp types
smp_type_break <- smp_features %>%
group_by(smp_smptype) %>%
summarise(count = n()) %>%
select(Type = smp_smptype, count)

#number of unmonitored smps
unmonitored_smp_type_break <- unmonitored_smp_features %>%
group_by(smp_smptype) %>%
summarise(count = n()) %>%
select(Type = smp_smptype, count)
The following Pie chart shows the break-down of all SMPs (monitored
and unmonitored).


#combining all smps (monitored and unmonitored) and get fractions based on type of smp-finally normalize them
total_smp <- unmonitored_smp_type_break %>%
full_join(smp_type_break, by="Type")
total_smp[is.na(total_smp)] <- 0
total_smp <- total_smp %>%
mutate(total_number = count.x+count.y) %>%
select(Type, total_number)
total_smp <- total_smp %>%
mutate(sum_all = sum(total_number)) %>%
mutate(percent_all = (total_number/sum_all)*100)
#get the percent of monitored SMP
smp_type_break_fraction <- smp_type_break %>%
mutate(sum_all = sum(count)) %>%
mutate(percent_monitored = (count/sum_all)*100)
#normalize the monitored smp by the total smp percents
normalized_fractions <- smp_type_break_fraction %>%
full_join(total_smp, by="Type") %>%
mutate(normalized_percent = percent_monitored/percent_all) %>%
select(Type, percent_monitored, percent_all, normalized_percent)
normalized_fractions[is.na(normalized_fractions)] <- 0
The following table is aimed to identify the over-representing
(normalized percent > 1) and under-representing (normalized percent
<1) SMP types.
#calculating the normalized percentage of smp types
kable(arrange(normalized_fractions, normalized_percent), caption = "Normalized SMP Break-down")
Normalized SMP Break-down
| Green Roof |
0.0000000 |
0.1490313 |
0.0000000 |
| Stormwater Tree |
0.0000000 |
4.1728763 |
0.0000000 |
| Bumpout |
2.5862069 |
8.4947839 |
0.3044465 |
| Swale |
1.2931034 |
2.5335320 |
0.5103955 |
| Planter |
5.8189655 |
7.5260805 |
0.7731734 |
| Infiltration/Storage Trench |
26.0775862 |
29.5081967 |
0.8837404 |
| Basin |
0.2155172 |
0.2235469 |
0.9640805 |
| Rain Garden |
12.0689655 |
11.1028316 |
1.0870169 |
| Tree Trench |
50.6465517 |
35.6929955 |
1.4189493 |
| Pervious Paving |
0.4310345 |
0.2980626 |
1.4461207 |
| Drainage Well |
0.8620690 |
0.2980626 |
2.8922414 |
The table above shows Tree trenches are over-represented in our CWL
data, while green roof, stormwater tree, bumpout, swale and planters are
under-represented (due to monitoring limitation, etc).
The following section is focused on establishing the design metrics
range for SMPs in the unmonitored SMP list. These design metrics include
drainage area, storm size managed and loading ratio.
#rawstormsizemanaged-in , sys_impervda_ft2, and loading ratio metrics gathering
table_all <- unmonitored_smp_features %>%
left_join(sysbdv, by="system_id") %>%
mutate(loading_ratio = sys_lrtotalda_ft2 )
#Clustring analysis based on 3 features of drainage area, loading ratio, and storm sized managed
clustered_moniored <- table_all %>%
select(system_id, sys_impervda_ft2, loading_ratio, sys_rawstormsizemanaged_in) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_moniored
normalized_cluster[,2:4] <- scale(clustered_moniored[,2:4])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:4], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:4], centers = 4)
# Store the cluster assignments back into the clustering data frame object
clustered_moniored$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_moniored$cluster)
1 2 3 4
21 279 136 11
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_moniored %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
17695.05 |
68.36332 |
1.491118 |
| 2 |
20363.52 |
12.75067 |
1.886491 |
| 3 |
17350.55 |
23.52892 |
1.212609 |
| 4 |
62204.82 |
10.56821 |
3.843215 |
ggplot(data = clustered_moniored, aes(x = loading_ratio, y = sys_rawstormsizemanaged_in, color = cluster)) +
geom_point()

plot_ly(clustered_moniored, x = ~sys_impervda_ft2, y = ~loading_ratio, z = ~sys_rawstormsizemanaged_in) %>%
add_markers(color = ~cluster)
In order to have a more relevant clustering method that distinguishes
between general types of systems (lined vs unlined or bioretention vs
bio infiltration), the unmonitored SMPs were devided into broad
categories of Bioinfiltration, Bioretention (lined), Bioretention
(unlined), Subsurface infiltration, Subsurface slow release (lined), and
Subsurface slow release (unlined). This is done by a system-level
feature called sys_modelinputcategory. The code chunk below shows a
break down of these SMPs. Please note that green roof and permeable
pavements are not included due to the low number.
#sys_modelinputcategory categories
sys_cat <- table_all %>%
select(system_id, sys_modelinputcategory)%>%
distinct %>%
group_by(sys_modelinputcategory) %>%
summarise(count = n())
kable(sys_cat)
| Bioinfiltration |
124 |
| Bioretention (lined) |
29 |
| Bioretention (unlined) |
83 |
| Green Roof |
2 |
| Permeable Pavement |
1 |
| Subsurface infiltration |
159 |
| Subsurface slow release (lined) |
113 |
| Subsurface slow release (unlined) |
113 |
clustered_Bioinfiltration <- table_all %>%
filter(sys_modelinputcategory == "Bioinfiltration") %>%
select(system_id, sys_impervda_ft2, loading_ratio, sys_rawstormsizemanaged_in, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_Bioinfiltration
normalized_cluster[,2:4] <- scale(clustered_Bioinfiltration[,2:4])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:4], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:4], centers = 4)
# Store the cluster assignments back into the clustering data frame object
clustered_Bioinfiltration$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_Bioinfiltration$cluster)
1 2 3 4
17 31 72 4
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_Bioinfiltration %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
11184.24 |
40.58019 |
1.063568 |
| 2 |
51515.00 |
15.79839 |
1.752800 |
| 3 |
15718.52 |
12.39893 |
1.778769 |
| 4 |
22358.50 |
10.18006 |
4.348037 |
#3 D plot
plot_ly(clustered_Bioinfiltration, x = ~sys_impervda_ft2, y = ~loading_ratio, z = ~sys_rawstormsizemanaged_in) %>%
add_markers(color = ~cluster)
Bioretention (lined) clustering. Note that loading ratio field is not
applicable here.
clustered_Bioreten_lined <- table_all %>%
filter(sys_modelinputcategory == "Bioretention (lined)") %>%
select(system_id, sys_impervda_ft2, sys_rawstormsizemanaged_in, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_Bioreten_lined
normalized_cluster[,2:3] <- scale(clustered_Bioreten_lined[,2:3])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:3], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:3], centers = 2)
# Store the cluster assignments back into the clustering data frame object
clustered_Bioreten_lined$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_Bioreten_lined$cluster)
1 2
5 24
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_Bioreten_lined %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
73919.40 |
2.270016 |
| 2 |
18291.83 |
1.473926 |
#3 D plot
plot_ly(clustered_Bioreten_lined, x = ~sys_impervda_ft2, y = ~sys_rawstormsizemanaged_in) %>%
add_markers(color = ~cluster)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Bioretention (unlined) clustering.
clustered_Bioreten_unlined <- table_all %>%
filter(sys_modelinputcategory == "Bioretention (unlined)") %>%
select(system_id, sys_impervda_ft2, sys_rawstormsizemanaged_in, loading_ratio, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_Bioreten_unlined
normalized_cluster[,2:4] <- scale(clustered_Bioreten_unlined[,2:4])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:4], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:4], centers = 3)
# Store the cluster assignments back into the clustering data frame object
clustered_Bioreten_unlined$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_Bioreten_unlined$cluster)
1 2 3
9 21 53
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_Bioreten_unlined %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
7046.333 |
3.309078 |
4.263439 |
| 2 |
42812.095 |
1.525561 |
20.624402 |
| 3 |
16789.575 |
1.639162 |
12.959101 |
#3 D plot
plot_ly(clustered_Bioreten_unlined, x = ~sys_impervda_ft2, y = ~sys_rawstormsizemanaged_in, z= ~loading_ratio) %>%
add_markers(color = ~cluster)
clustered_subsurface <- table_all %>%
filter(sys_modelinputcategory == "Subsurface infiltration") %>%
select(system_id, sys_impervda_ft2, sys_rawstormsizemanaged_in, loading_ratio, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_subsurface
normalized_cluster[,2:4] <- scale(clustered_subsurface[,2:4])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:4], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:4], centers = 2)
# Store the cluster assignments back into the clustering data frame object
clustered_subsurface$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_subsurface$cluster)
1 2
99 26
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_subsurface %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
19525.382 |
1.837962 |
12.69806 |
| 2 |
7850.692 |
1.030724 |
31.54683 |
#3 D plot
plot_ly(clustered_subsurface, x = ~sys_impervda_ft2, y = ~sys_rawstormsizemanaged_in, z= ~loading_ratio) %>%
add_markers(color = ~cluster)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
clustered_slowrel_lined <- table_all %>%
filter(sys_modelinputcategory == "Subsurface slow release (lined)") %>%
select(system_id, sys_impervda_ft2, sys_rawstormsizemanaged_in, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_slowrel_lined
normalized_cluster[,2:3] <- scale(clustered_slowrel_lined[,2:3])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:3], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:3], centers = 2)
# Store the cluster assignments back into the clustering data frame object
clustered_slowrel_lined$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_slowrel_lined$cluster)
1 2
58 55
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_slowrel_lined %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
13139.92 |
1.195020 |
| 2 |
20312.98 |
1.720648 |
#3 D plot
plot_ly(clustered_slowrel_lined, x = ~sys_impervda_ft2, y = ~sys_rawstormsizemanaged_in) %>%
add_markers(color = ~cluster)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
clustered_slowrel_unlined <- table_all %>%
filter(sys_modelinputcategory == "Subsurface slow release (unlined)") %>%
select(system_id, sys_impervda_ft2, sys_rawstormsizemanaged_in, loading_ratio, sys_modelinputcategory) %>%
na.omit() %>%
distinct()
#normalze using mean-sd standardization
normalized_cluster <- clustered_slowrel_unlined
normalized_cluster[,2:3] <- scale(clustered_slowrel_unlined[,2:3])
#Elbow method shows a subtle elbow at cluster 4-hence 4 clusters is optimum
#number of clusters
fviz_nbclust(normalized_cluster[,2:3], kmeans, method = "wss")

#k-means
# Cluster using kmeans with five clusters
cluster_solution <- kmeans(normalized_cluster[,2:3], centers = 2)
# Store the cluster assignments back into the clustering data frame object
clustered_slowrel_unlined$cluster <-factor(cluster_solution$cluster)
# Look at the distribution of cluster assignments
table(clustered_slowrel_unlined$cluster)
1 2
61 52
# Group by the cluster assignment and calculate averages
sys_clus_avg <- clustered_slowrel_unlined %>%
group_by(cluster) %>%
summarize_if(is.numeric, mean)
# View the resulting table
kable(sys_clus_avg)
| 1 |
18886.52 |
1.910538 |
19.26955 |
| 2 |
16819.60 |
1.337858 |
34.30980 |
#3 D plot
plot_ly(clustered_slowrel_unlined, x = ~sys_impervda_ft2, y = ~sys_rawstormsizemanaged_in, z = ~loading_ratio) %>%
add_markers(color = ~cluster)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Warning in RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels
Upon clustering the systems, the data will be collected in a unified
data frame for stratified sampling. The stratified sampling creates a
balanced list of systems that are reflective of the size of each smp
type and that of the internal clusters. For example, the code below has
generated 58 system (~ 10% of total unmonitored systems); the size of
each system type is proportional to that of the population, and within
each type of systems, a proportional number of systems has been chosen
from each cluster e.g., in Bioinfiltration type systems, 7 systems are
randomly chosen from cluster 3, 3 systems from cluster 2, and 2 systems
from cluster 1.
#binding all sub-type groups into one table
sys_clustered_all <- bind_rows(clustered_Bioinfiltration[,c("system_id","cluster","sys_modelinputcategory")], clustered_Bioreten_lined[,c("system_id","cluster","sys_modelinputcategory")], clustered_Bioreten_unlined[,c("system_id","cluster","sys_modelinputcategory")], clustered_slowrel_lined[,c("system_id","cluster","sys_modelinputcategory")], clustered_slowrel_unlined[,c("system_id","cluster","sys_modelinputcategory")], clustered_subsurface[,c("system_id","cluster","sys_modelinputcategory")])
#sampling code
stratified_sample <- sys_clustered_all %>%
group_by(sys_modelinputcategory, cluster) %>%
sample_frac(size=0.1)
kable(stratified_sample)
| 1023-8 |
1 |
Bioinfiltration |
| 282-3 |
1 |
Bioinfiltration |
| 1281-31 |
2 |
Bioinfiltration |
| 1315-6 |
2 |
Bioinfiltration |
| 1383-1 |
2 |
Bioinfiltration |
| 281-1 |
3 |
Bioinfiltration |
| 1138-3 |
3 |
Bioinfiltration |
| 1138-5 |
3 |
Bioinfiltration |
| 290-2 |
3 |
Bioinfiltration |
| 410-2 |
3 |
Bioinfiltration |
| 1138-2 |
3 |
Bioinfiltration |
| 416-1 |
3 |
Bioinfiltration |
| 1007-2 |
2 |
Bioretention (lined) |
| 1347-2 |
2 |
Bioretention (lined) |
| 641-5 |
1 |
Bioretention (unlined) |
| 595-8 |
2 |
Bioretention (unlined) |
| 1288-5 |
2 |
Bioretention (unlined) |
| 1198-7 |
3 |
Bioretention (unlined) |
| 1053-8 |
3 |
Bioretention (unlined) |
| 595-4 |
3 |
Bioretention (unlined) |
| 1265-9 |
3 |
Bioretention (unlined) |
| 162-2 |
3 |
Bioretention (unlined) |
| 1298-2 |
1 |
Subsurface infiltration |
| 46-1 |
1 |
Subsurface infiltration |
| 1288-10 |
1 |
Subsurface infiltration |
| 1202-10 |
1 |
Subsurface infiltration |
| 1281-41 |
1 |
Subsurface infiltration |
| 1051-7 |
1 |
Subsurface infiltration |
| 994-4 |
1 |
Subsurface infiltration |
| 1010-5 |
1 |
Subsurface infiltration |
| 1287-3 |
1 |
Subsurface infiltration |
| 280-3 |
1 |
Subsurface infiltration |
| 1298-1 |
2 |
Subsurface infiltration |
| 441-15 |
2 |
Subsurface infiltration |
| 1265-12 |
2 |
Subsurface infiltration |
| 525-2 |
1 |
Subsurface slow release (lined) |
| 1299-1 |
1 |
Subsurface slow release (lined) |
| 1202-6 |
1 |
Subsurface slow release (lined) |
| 1202-7 |
1 |
Subsurface slow release (lined) |
| 1202-2 |
1 |
Subsurface slow release (lined) |
| 1011-4 |
1 |
Subsurface slow release (lined) |
| 1279-13 |
2 |
Subsurface slow release (lined) |
| 1051-5 |
2 |
Subsurface slow release (lined) |
| 1279-2 |
2 |
Subsurface slow release (lined) |
| 1129-4 |
2 |
Subsurface slow release (lined) |
| 1307-4 |
2 |
Subsurface slow release (lined) |
| 1267-2 |
2 |
Subsurface slow release (lined) |
| 246-2 |
1 |
Subsurface slow release (unlined) |
| 443-9 |
1 |
Subsurface slow release (unlined) |
| 578-5 |
1 |
Subsurface slow release (unlined) |
| 1139-23 |
1 |
Subsurface slow release (unlined) |
| 443-10 |
1 |
Subsurface slow release (unlined) |
| 1287-4 |
1 |
Subsurface slow release (unlined) |
| 1240-1 |
2 |
Subsurface slow release (unlined) |
| 1051-3 |
2 |
Subsurface slow release (unlined) |
| 1394-1 |
2 |
Subsurface slow release (unlined) |
| 1202-9 |
2 |
Subsurface slow release (unlined) |
| 1359-5 |
2 |
Subsurface slow release (unlined) |
LS0tDQp0aXRsZTogIlNNUCBwb3B1bGF0aW9uIGFzc2VzbWVudCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KYXV0aG9yOiAiRmFyc2hhZCBFYnJhaGltaSwgSmFuLzMwLzIwMjMiDQotLS0NCg0KVGhlIGdvYWwgb2YgdGhpcyBhbmFseXNpcyBpcyB0byBhc3Nlc3MgdGhlIFNNUCBwb3B1bGF0aW9uIHdpdGggQ1dMIG1vbml0b3JpbmcgZGF0YSwgY2F0ZWdvcml6ZSB0aGVtIGFuZCBmaW5kIHRoZSB1bmRlcnJlcHJlc2VudGVkIHNtcCBmZWF0dXJlcyBpbiBvdXIgZGF0YSBzZXQuIFRoaXMgaXMgdG8gZW5zdXJlIG91ciBtb25pdG9yaW5nIGVmZm9ydCByZXN1bHRzIGluIGEgbW9yZSBjb21wcmVoZW5zaXZlIGRhdGEgc2V0IHRoYXQgY292ZXJzIGFsbCB0eXBlcyBvZiBTTVBzIHdpdGggdmFyeWluZyBkZXNpZ24gbWV0cmljcyBzdWNoIGFzIGxvYWRpbmcgcmF0aW9zLiBUaGUgb3V0cHV0IG9mIHRoaXMgYW5hbHlzaXMgY2FuIGFzc2lzdCB0aGUgZGF0YSBjb2xsZWN0aW9uIHRlYW0gd2l0aCB0aGVpciBmdXR1cmUgc2l0ZSBzZWxlY3Rpb24gcHJvY2Vzcy4NCg0KYGBge3Igc2VjdGlvbiAxLCBMb2FkaW5nIGxpYnJhcmllcyBhbmQgcXVlcnlpbmcgc21wIGRhdGEgfQ0KI0xpYnJhcmllcw0KICAgICAgbGlicmFyeShvZGJjKQ0KICAgICAgbGlicmFyeShEQkkpDQogICAgICBsaWJyYXJ5KGx1YnJpZGF0ZSkNCiAgICAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KICAgICAgbGlicmFyeShzdGF0cykNCiAgICAgIGxpYnJhcnkoZ3JpZEV4dHJhKQ0KICAgICAgbGlicmFyeShncmlkKQ0KICAgICAgbGlicmFyeShndGFibGUpDQogICAgICBsaWJyYXJ5KGdndGV4dCkNCiAgICAgIGxpYnJhcnkoZHBseXIpDQogICAgICBsaWJyYXJ5KGdncGxvdDIpDQogICAgICBsaWJyYXJ5KGtuaXRyKQ0KICAgICAgbGlicmFyeShwbG90bHkpDQogICAgICBsaWJyYXJ5KGNsdXN0ZXIpDQogICAgICBsaWJyYXJ5KGZhY3RvZXh0cmEpDQojIERCIFBHMTQNCiAgICBjb24gPC0gZGJDb25uZWN0KG9kYmM6Om9kYmMoKSwgZHNuID0gIm1hcnMxNF9kYXRhIiwgdWlkID0gU3lzLmdldGVudigic2hpbnlfdWlkIiksIHB3ZCA9IFN5cy5nZXRlbnYoInNoaW55X3B3ZCIpLCBNYXhMb25nVmFyY2hhclNpemUgPSA4MTkwKQ0KDQojR2V0dGluZyBsaXN0IG9mIFNNUHMNCiAgICBjd2xfc21wIDwtIGRiR2V0UXVlcnkoY29uLCJTRUxFQ1QgRElTVElOQ1Qgc21wX2lkDQogICAgICAgICAgIEZST00gZmllbGR3b3JrLnZpd19kZXBsb3ltZW50X2Z1bGxfY3dsIikNCiAgICANCiNHZXR0aW5nIHRoZSBncmVlbml0IGluZm8NCiAgICBzbXBiZHYgPC0gZGJHZXRRdWVyeShjb24sIlNFTEVDVCAqIEZST00gZXh0ZXJuYWwudGJsX3NtcGJkdiIpDQogICAgc3lzYmR2IDwtIGRiR2V0UXVlcnkoY29uLCJTRUxFQ1QgKiBGUk9NIGV4dGVybmFsLnRibF9zeXN0ZW1iZHYiKQ0KICAgIGdyZWVuaXRfdW5pZmllZCA8LWRiR2V0UXVlcnkoY29uLCJTRUxFQ1QgKiBGUk9NIGV4dGVybmFsLnZpd19ncmVlbml0X3VuaWZpZWQiKQ0KDQojIGpvaW4gdGhlIGdyZWVuaXQgdGFibGUgd2l0aCBvdXIgc21wIGxpc3QNCiAgICBzbXBfZmVhdHVyZXMgPC0gY3dsX3NtcCAlPiUgDQogICAgICBpbm5lcl9qb2luKHNtcGJkdiwgYnk9InNtcF9pZCIpDQojIFVubW9uaXRvcmVkIFNNUHMNCiAgICB1bm1vbml0b3JlZF9zbXAgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcRmFyc2hhZC5FYnJhaGltaVxcT25lRHJpdmUgLSBDaXR5IG9mIFBoaWxhZGVscGhpYVxcR2l0aHViIFByb2plY3RzXFxzbXAtcG9wdWxhdGlvbi1hc3Nlc21lbnRcXHVubW9uaXRvcmVkX3NpdGVzLmNzdiIpICU+JQ0KICAgICAgc2VsZWN0KHNtcF9pZCA9IFNNUC5JRCkgJT4lDQogICAgICBkaXN0aW5jdCgpDQojIHVubW9uaXRvcmVkIHNtcF9mZWF0dXJlcw0KICAgIHVubW9uaXRvcmVkX3NtcF9mZWF0dXJlcyA8LSB1bm1vbml0b3JlZF9zbXAgJT4lDQogICAgICBpbm5lcl9qb2luKHNtcGJkdiwgYnk9InNtcF9pZCIpDQpgYGANCg0KVGhlIGZvbGxvd2luZyBjb2RlIGNodW5rIGNhbGN1bGF0ZXMgdGhlIGJyZWFrLWRvd24gb2YgU01QIHR5cGVzIHdpdGggQ1dMIGRhdGEuDQoNCmBgYHtyIHNlY3Rpb24gMiwgTW9uaXRvcmVkIFNNUCBicmVhay1kb3duIGJhc2VkIG9uIHR5cGV9DQojbnVtYmVyIG9mIHNtcCB0eXBlcw0Kc21wX3R5cGVfYnJlYWsgPC0gc21wX2ZlYXR1cmVzICU+JSANCiAgZ3JvdXBfYnkoc21wX3NtcHR5cGUpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBzZWxlY3QoVHlwZSA9IHNtcF9zbXB0eXBlLCBjb3VudCkNCmBgYA0KDQpgYGB7ciBzZWN0aW9uIDMgcGllIGNoYXJ0IG9mIG1vbml0b3JlZCBTTVBzLCBlY2hvPUZhbHNlfQ0KZ2dwbG90KHNtcF90eXBlX2JyZWFrLCBhZXMoeD0iIiwgeT0gY291bnQsIGZpbGw9VHlwZSkpK2dlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpK2Nvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkNCmBgYA0KDQpgYGB7ciBzZWN0aW9uIDQsIGxvb2tpbmcgYXQgdGhlIHVubW9uaXRvcmVkIFNNUHMgdG8gc2VlIHRoZSBicmVhay1kb3dufQ0KI251bWJlciBvZiB1bm1vbml0b3JlZCBzbXBzDQp1bm1vbml0b3JlZF9zbXBfdHlwZV9icmVhayA8LSB1bm1vbml0b3JlZF9zbXBfZmVhdHVyZXMgJT4lIA0KICBncm91cF9ieShzbXBfc21wdHlwZSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIHNlbGVjdChUeXBlID0gc21wX3NtcHR5cGUsIGNvdW50KQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgUGllIGNoYXJ0IHNob3dzIHRoZSBicmVhay1kb3duIG9mIGFsbCBTTVBzIChtb25pdG9yZWQgYW5kIHVubW9uaXRvcmVkKS4NCg0KYGBge3Igc2V0aW9uIDUgcGllIGNoYXJ0IG9mIHVubW9uaXRvcmVkIFNNUHMsIGVjaG89RkFMU0V9DQpnZ3Bsb3QodW5tb25pdG9yZWRfc21wX3R5cGVfYnJlYWssIGFlcyh4PSIiLCB5PSBjb3VudCwgZmlsbD1UeXBlKSkrZ2VvbV9iYXIod2lkdGggPSAxLCBzdGF0ID0gImlkZW50aXR5IikrY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKQ0KYGBgDQoNCmBgYHtyIHNlY3Rpb24gNiBmdWxsIGpvaW4gdGhlIHVubW9uaXRvcmVkIGFuZCBtb25pdG9yZWQsIGVjaG89RkFMU0V9DQojZnVsbCBqb2luIHRoZSB1bm1vbml0b3JlZCBhbmQgbW9uaXJvcmVkIGFuZCBjcmVhdGUgYSBjb2x1bW4gdG8gc3VtIHRoZW0gdXANCnNtcF9icmVha2R3b25fZnVsbCA8LSBzbXBfdHlwZV9icmVhayAlPiUNCiAgZnVsbF9qb2luKHVubW9uaXRvcmVkX3NtcF90eXBlX2JyZWFrLCBieT0iVHlwZSIpICU+JQ0KICBzZWxlY3QoVHlwZSwgY291bnRfbW9uaXRvcmVkID0gY291bnQueCwgY291bnRfdW5tb25pdG9yZWQgPSBjb3VudC55KQ0KDQojcmVwbGFjZSBuYSB3aXRoIHplcm8NCnNtcF9icmVha2R3b25fZnVsbFtpcy5uYShzbXBfYnJlYWtkd29uX2Z1bGwpXSA8LSAwDQoNCiNtdXRhdGUgdGhlIHRoaXJkIGNvbHVtbg0Kc21wX2JyZWFrZHdvbl9mdWxsIDwtIHNtcF9icmVha2R3b25fZnVsbCAlPiUNCiAgbXV0YXRlKHN1bV9hbGwgPSBjb3VudF9tb25pdG9yZWQgKyBjb3VudF91bm1vbml0b3JlZCkNCg0KI2RhdGEgZnJhbWUgZm9yIHBsb3R0aW5nIChvbmx5IHR3byBjb2x1bW5zKQ0KcGl2b3RfZGYgPC0gc21wX2JyZWFrZHdvbl9mdWxsICU+JQ0KICBzZWxlY3QoVHlwZSwgY291bnRfbW9uaXRvcmVkLCBzdW1fYWxsKQ0KDQpkZl9sb25nZXIgPC0gcGl2b3RfbG9uZ2VyKHBpdm90X2RmLCBjb2xzID0gYygiY291bnRfbW9uaXRvcmVkIiwgInN1bV9hbGwiKSwgbmFtZXNfdG8gPSAiY2F0ZWdvcnkiLCB2YWx1ZXNfdG8gPSAiY291bnQiKQ0KDQojUGxvdA0KZ2dwbG90KGRmX2xvbmdlcixhZXMoeCA9IFR5cGUsIHkgPSBjb3VudCwgZmlsbD0gY2F0ZWdvcnkpKSArDQogICAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKCkpKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTYsIGFuZ2xlID0gMzUpLA0KICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSkNCg0KYGBgDQoNCmBgYHtyIHNlY3Rpb24gNywgYWRkaW5nIHRoZSBtb25pdG9yZWQgYW5kIHVubW9uaW9yZWR9DQojY29tYmluaW5nIGFsbCBzbXBzIChtb25pdG9yZWQgYW5kIHVubW9uaXRvcmVkKSBhbmQgZ2V0IGZyYWN0aW9ucyBiYXNlZCBvbiB0eXBlIG9mIHNtcC1maW5hbGx5IG5vcm1hbGl6ZSB0aGVtDQp0b3RhbF9zbXAgPC0gdW5tb25pdG9yZWRfc21wX3R5cGVfYnJlYWsgJT4lDQogIGZ1bGxfam9pbihzbXBfdHlwZV9icmVhaywgYnk9IlR5cGUiKQ0KdG90YWxfc21wW2lzLm5hKHRvdGFsX3NtcCldIDwtIDANCnRvdGFsX3NtcCA8LSB0b3RhbF9zbXAgJT4lDQogIG11dGF0ZSh0b3RhbF9udW1iZXIgPSBjb3VudC54K2NvdW50LnkpICU+JQ0KICBzZWxlY3QoVHlwZSwgdG90YWxfbnVtYmVyKQ0KdG90YWxfc21wIDwtIHRvdGFsX3NtcCAlPiUNCiAgICBtdXRhdGUoc3VtX2FsbCA9IHN1bSh0b3RhbF9udW1iZXIpKSAlPiUNCiAgICBtdXRhdGUocGVyY2VudF9hbGwgPSAodG90YWxfbnVtYmVyL3N1bV9hbGwpKjEwMCkNCg0KI2dldCB0aGUgcGVyY2VudCBvZiBtb25pdG9yZWQgU01QDQpzbXBfdHlwZV9icmVha19mcmFjdGlvbiA8LSBzbXBfdHlwZV9icmVhayAlPiUNCiAgICBtdXRhdGUoc3VtX2FsbCA9IHN1bShjb3VudCkpICU+JQ0KICAgIG11dGF0ZShwZXJjZW50X21vbml0b3JlZCA9IChjb3VudC9zdW1fYWxsKSoxMDApDQoNCiNub3JtYWxpemUgdGhlIG1vbml0b3JlZCBzbXAgYnkgdGhlIHRvdGFsIHNtcCBwZXJjZW50cw0Kbm9ybWFsaXplZF9mcmFjdGlvbnMgPC0gc21wX3R5cGVfYnJlYWtfZnJhY3Rpb24gJT4lDQogIGZ1bGxfam9pbih0b3RhbF9zbXAsIGJ5PSJUeXBlIikgJT4lDQogIG11dGF0ZShub3JtYWxpemVkX3BlcmNlbnQgPSBwZXJjZW50X21vbml0b3JlZC9wZXJjZW50X2FsbCkgJT4lDQogIHNlbGVjdChUeXBlLCBwZXJjZW50X21vbml0b3JlZCwgcGVyY2VudF9hbGwsIG5vcm1hbGl6ZWRfcGVyY2VudCkNCg0Kbm9ybWFsaXplZF9mcmFjdGlvbnNbaXMubmEobm9ybWFsaXplZF9mcmFjdGlvbnMpXSA8LSAwDQpgYGANCg0KVGhlIGZvbGxvd2luZyB0YWJsZSBpcyBhaW1lZCB0byBpZGVudGlmeSB0aGUgb3Zlci1yZXByZXNlbnRpbmcgKG5vcm1hbGl6ZWQgcGVyY2VudCBcPiAxKSBhbmQgdW5kZXItcmVwcmVzZW50aW5nIChub3JtYWxpemVkIHBlcmNlbnQgXDwxKSBTTVAgdHlwZXMuDQoNCmBgYHtyfQ0KI2NhbGN1bGF0aW5nIHRoZSBub3JtYWxpemVkIHBlcmNlbnRhZ2Ugb2Ygc21wIHR5cGVzDQprYWJsZShhcnJhbmdlKG5vcm1hbGl6ZWRfZnJhY3Rpb25zLCBub3JtYWxpemVkX3BlcmNlbnQpLCBjYXB0aW9uID0gIk5vcm1hbGl6ZWQgU01QIEJyZWFrLWRvd24iKQ0KYGBgDQoNClRoZSB0YWJsZSBhYm92ZSBzaG93cyBUcmVlIHRyZW5jaGVzIGFyZSBvdmVyLXJlcHJlc2VudGVkIGluIG91ciBDV0wgZGF0YSwgd2hpbGUgZ3JlZW4gcm9vZiwgc3Rvcm13YXRlciB0cmVlLCBidW1wb3V0LCBzd2FsZSBhbmQgcGxhbnRlcnMgYXJlIHVuZGVyLXJlcHJlc2VudGVkIChkdWUgdG8gbW9uaXRvcmluZyBsaW1pdGF0aW9uLCBldGMpLg0KDQpUaGUgZm9sbG93aW5nIHNlY3Rpb24gaXMgZm9jdXNlZCBvbiBlc3RhYmxpc2hpbmcgdGhlIGRlc2lnbiBtZXRyaWNzIHJhbmdlIGZvciBTTVBzIGluIHRoZSB1bm1vbml0b3JlZCBTTVAgbGlzdC4gVGhlc2UgZGVzaWduIG1ldHJpY3MgaW5jbHVkZSBkcmFpbmFnZSBhcmVhLCBzdG9ybSBzaXplIG1hbmFnZWQgYW5kIGxvYWRpbmcgcmF0aW8uDQoNCmBgYHtyIHNlY3Rpb24gOCwgcmF3c3Rvcm1zaXplbWFuYWdlZC1pbiAsIHN5c19pbXBlcnZkYV9mdDIsIGFuZCBsb2FkaW5nIHJhdGlvIG1ldHJpY3MgZ2F0aGVyaW5nfQ0KI3Jhd3N0b3Jtc2l6ZW1hbmFnZWQtaW4gLCBzeXNfaW1wZXJ2ZGFfZnQyLCBhbmQgbG9hZGluZyByYXRpbyBtZXRyaWNzIGdhdGhlcmluZw0KDQp0YWJsZV9hbGwgPC0gdW5tb25pdG9yZWRfc21wX2ZlYXR1cmVzICU+JQ0KICBsZWZ0X2pvaW4oc3lzYmR2LCBieT0ic3lzdGVtX2lkIikgJT4lDQogIG11dGF0ZShsb2FkaW5nX3JhdGlvID0gc3lzX2xydG90YWxkYV9mdDIgKQ0KYGBgDQoNCmBgYHtyIHNlY3Rpb24gOX0NCiNDbHVzdHJpbmcgYW5hbHlzaXMgYmFzZWQgb24gMyBmZWF0dXJlcyBvZiBkcmFpbmFnZSBhcmVhLCBsb2FkaW5nIHJhdGlvLCBhbmQgc3Rvcm0gc2l6ZWQgbWFuYWdlZA0KDQpjbHVzdGVyZWRfbW9uaW9yZWQgPC0gdGFibGVfYWxsICU+JQ0KICBzZWxlY3Qoc3lzdGVtX2lkLCBzeXNfaW1wZXJ2ZGFfZnQyLCBsb2FkaW5nX3JhdGlvLCBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojbm9ybWFsemUgdXNpbmcgbWVhbi1zZCBzdGFuZGFyZGl6YXRpb24NCm5vcm1hbGl6ZWRfY2x1c3RlciA8LSBjbHVzdGVyZWRfbW9uaW9yZWQNCm5vcm1hbGl6ZWRfY2x1c3RlclssMjo0XSA8LSBzY2FsZShjbHVzdGVyZWRfbW9uaW9yZWRbLDI6NF0pDQoNCiNFbGJvdyBtZXRob2Qgc2hvd3MgYSBzdWJ0bGUgZWxib3cgYXQgY2x1c3RlciA0LWhlbmNlIDQgY2x1c3RlcnMgaXMgb3B0aW11bQ0KI251bWJlciBvZiBjbHVzdGVycw0KZnZpel9uYmNsdXN0KG5vcm1hbGl6ZWRfY2x1c3RlclssMjo0XSwga21lYW5zLCBtZXRob2QgPSAid3NzIikNCg0KI2stbWVhbnMgDQojIENsdXN0ZXIgdXNpbmcga21lYW5zIHdpdGggZml2ZSBjbHVzdGVycw0KY2x1c3Rlcl9zb2x1dGlvbiA8LSBrbWVhbnMobm9ybWFsaXplZF9jbHVzdGVyWywyOjRdLCBjZW50ZXJzID0gNCkNCg0KIyBTdG9yZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBiYWNrIGludG8gdGhlIGNsdXN0ZXJpbmcgZGF0YSBmcmFtZSBvYmplY3QNCmNsdXN0ZXJlZF9tb25pb3JlZCRjbHVzdGVyIDwtZmFjdG9yKGNsdXN0ZXJfc29sdXRpb24kY2x1c3RlcikgDQoNCiMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNsdXN0ZXIgYXNzaWdubWVudHMNCnRhYmxlKGNsdXN0ZXJlZF9tb25pb3JlZCRjbHVzdGVyKQ0KYGBgDQoNCmBgYHtyIHNlY3Rpb24gMTAgYW5hbHl6aW5nIHRoZSBjbHVzdGVyIGZlYXR1cmVzfQ0KIyBHcm91cCBieSB0aGUgY2x1c3RlciBhc3NpZ25tZW50IGFuZCBjYWxjdWxhdGUgYXZlcmFnZXMNCnN5c19jbHVzX2F2ZyA8LSBjbHVzdGVyZWRfbW9uaW9yZWQgJT4lDQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogICAgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIG1lYW4pDQoNCiMgVmlldyB0aGUgcmVzdWx0aW5nIHRhYmxlDQprYWJsZShzeXNfY2x1c19hdmcpDQpgYGANCg0KYGBge3IgMkQgUGxvdH0NCmdncGxvdChkYXRhID0gY2x1c3RlcmVkX21vbmlvcmVkLCBhZXMoeCA9IGxvYWRpbmdfcmF0aW8sIHkgPSBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbiwgY29sb3IgPSBjbHVzdGVyKSkgKw0KICAgIGdlb21fcG9pbnQoKQ0KYGBgDQoNCmBgYHtyIDNEIHBsb3R9DQpwbG90X2x5KGNsdXN0ZXJlZF9tb25pb3JlZCwgeCA9IH5zeXNfaW1wZXJ2ZGFfZnQyLCB5ID0gfmxvYWRpbmdfcmF0aW8sIHogPSB+c3lzX3Jhd3N0b3Jtc2l6ZW1hbmFnZWRfaW4pICU+JQ0KICBhZGRfbWFya2Vycyhjb2xvciA9IH5jbHVzdGVyKQ0KYGBgDQoNCkluIG9yZGVyIHRvIGhhdmUgYSBtb3JlIHJlbGV2YW50IGNsdXN0ZXJpbmcgbWV0aG9kIHRoYXQgZGlzdGluZ3Vpc2hlcyBiZXR3ZWVuIGdlbmVyYWwgdHlwZXMgb2Ygc3lzdGVtcyAobGluZWQgdnMgdW5saW5lZCBvciBiaW9yZXRlbnRpb24gdnMgYmlvIGluZmlsdHJhdGlvbiksIHRoZSB1bm1vbml0b3JlZCBTTVBzIHdlcmUgZGV2aWRlZCBpbnRvIGJyb2FkIGNhdGVnb3JpZXMgb2YgQmlvaW5maWx0cmF0aW9uLCBCaW9yZXRlbnRpb24gKGxpbmVkKSwgQmlvcmV0ZW50aW9uICh1bmxpbmVkKSwgU3Vic3VyZmFjZSBpbmZpbHRyYXRpb24sIFN1YnN1cmZhY2Ugc2xvdyByZWxlYXNlIChsaW5lZCksIGFuZCBTdWJzdXJmYWNlIHNsb3cgcmVsZWFzZSAodW5saW5lZCkuIFRoaXMgaXMgZG9uZSBieSBhIHN5c3RlbS1sZXZlbCBmZWF0dXJlIGNhbGxlZCBzeXNfbW9kZWxpbnB1dGNhdGVnb3J5LiBUaGUgY29kZSBjaHVuayBiZWxvdyBzaG93cyBhIGJyZWFrIGRvd24gb2YgdGhlc2UgU01Qcy4gUGxlYXNlIG5vdGUgdGhhdCBncmVlbiByb29mIGFuZCBwZXJtZWFibGUgcGF2ZW1lbnRzIGFyZSBub3QgaW5jbHVkZWQgZHVlIHRvIHRoZSBsb3cgbnVtYmVyLg0KDQpgYGB7ciBzZWN0aW9uIDExIHN5c19tb2RlbGlucHV0Y2F0ZWdvcnkgaXMgdXNlZCB0byBjYXRlZ29yaXplIHN5c3RlbXN9DQojc3lzX21vZGVsaW5wdXRjYXRlZ29yeSBjYXRlZ29yaWVzDQpzeXNfY2F0IDwtIHRhYmxlX2FsbCAlPiUNCiAgc2VsZWN0KHN5c3RlbV9pZCwgc3lzX21vZGVsaW5wdXRjYXRlZ29yeSklPiUNCiAgZGlzdGluY3QgJT4lDQogIGdyb3VwX2J5KHN5c19tb2RlbGlucHV0Y2F0ZWdvcnkpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpDQoNCmthYmxlKHN5c19jYXQpDQpgYGANCg0KYGBge3Igc2VjdGlvbiAxMiBjbHVzdGVyaW5nIEJpb2luZmlsdHJhdGlvbiB0eXBlIHN5c3RlbXMgfQ0KDQpjbHVzdGVyZWRfQmlvaW5maWx0cmF0aW9uIDwtIHRhYmxlX2FsbCAlPiUNCiAgZmlsdGVyKHN5c19tb2RlbGlucHV0Y2F0ZWdvcnkgPT0gIkJpb2luZmlsdHJhdGlvbiIpICU+JQ0KICBzZWxlY3Qoc3lzdGVtX2lkLCBzeXNfaW1wZXJ2ZGFfZnQyLCBsb2FkaW5nX3JhdGlvLCBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbiwgc3lzX21vZGVsaW5wdXRjYXRlZ29yeSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojbm9ybWFsemUgdXNpbmcgbWVhbi1zZCBzdGFuZGFyZGl6YXRpb24NCm5vcm1hbGl6ZWRfY2x1c3RlciA8LSBjbHVzdGVyZWRfQmlvaW5maWx0cmF0aW9uDQpub3JtYWxpemVkX2NsdXN0ZXJbLDI6NF0gPC0gc2NhbGUoY2x1c3RlcmVkX0Jpb2luZmlsdHJhdGlvblssMjo0XSkNCg0KI0VsYm93IG1ldGhvZCBzaG93cyBhIHN1YnRsZSBlbGJvdyBhdCBjbHVzdGVyIDQtaGVuY2UgNCBjbHVzdGVycyBpcyBvcHRpbXVtDQojbnVtYmVyIG9mIGNsdXN0ZXJzDQpmdml6X25iY2x1c3Qobm9ybWFsaXplZF9jbHVzdGVyWywyOjRdLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQ0KDQojay1tZWFucyANCiMgQ2x1c3RlciB1c2luZyBrbWVhbnMgd2l0aCBmaXZlIGNsdXN0ZXJzDQpjbHVzdGVyX3NvbHV0aW9uIDwtIGttZWFucyhub3JtYWxpemVkX2NsdXN0ZXJbLDI6NF0sIGNlbnRlcnMgPSA0KQ0KDQojIFN0b3JlIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIGJhY2sgaW50byB0aGUgY2x1c3RlcmluZyBkYXRhIGZyYW1lIG9iamVjdA0KY2x1c3RlcmVkX0Jpb2luZmlsdHJhdGlvbiRjbHVzdGVyIDwtZmFjdG9yKGNsdXN0ZXJfc29sdXRpb24kY2x1c3RlcikgDQoNCiMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNsdXN0ZXIgYXNzaWdubWVudHMNCnRhYmxlKGNsdXN0ZXJlZF9CaW9pbmZpbHRyYXRpb24kY2x1c3RlcikNCg0KIyBHcm91cCBieSB0aGUgY2x1c3RlciBhc3NpZ25tZW50IGFuZCBjYWxjdWxhdGUgYXZlcmFnZXMNCnN5c19jbHVzX2F2ZyA8LSBjbHVzdGVyZWRfQmlvaW5maWx0cmF0aW9uICU+JQ0KICAgIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICAgIHN1bW1hcml6ZV9pZihpcy5udW1lcmljLCBtZWFuKQ0KDQojIFZpZXcgdGhlIHJlc3VsdGluZyB0YWJsZQ0Ka2FibGUoc3lzX2NsdXNfYXZnKQ0KDQojMyBEIHBsb3QNCnBsb3RfbHkoY2x1c3RlcmVkX0Jpb2luZmlsdHJhdGlvbiwgeCA9IH5zeXNfaW1wZXJ2ZGFfZnQyLCB5ID0gfmxvYWRpbmdfcmF0aW8sIHogPSB+c3lzX3Jhd3N0b3Jtc2l6ZW1hbmFnZWRfaW4pICU+JQ0KICBhZGRfbWFya2Vycyhjb2xvciA9IH5jbHVzdGVyKQ0KYGBgDQoNCkJpb3JldGVudGlvbiAobGluZWQpIGNsdXN0ZXJpbmcuIE5vdGUgdGhhdCBsb2FkaW5nIHJhdGlvIGZpZWxkIGlzIG5vdCBhcHBsaWNhYmxlIGhlcmUuDQoNCmBgYHtyIHNlY3Rpb24gMTMgQmlvcmV0ZW50aW9uIGxpbmVkIGNsdXN0ZXJpbmd9DQoNCmNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZCA8LSB0YWJsZV9hbGwgJT4lDQogIGZpbHRlcihzeXNfbW9kZWxpbnB1dGNhdGVnb3J5ID09ICJCaW9yZXRlbnRpb24gKGxpbmVkKSIpICU+JQ0KICBzZWxlY3Qoc3lzdGVtX2lkLCBzeXNfaW1wZXJ2ZGFfZnQyLCBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbiwgc3lzX21vZGVsaW5wdXRjYXRlZ29yeSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojbm9ybWFsemUgdXNpbmcgbWVhbi1zZCBzdGFuZGFyZGl6YXRpb24NCm5vcm1hbGl6ZWRfY2x1c3RlciA8LSBjbHVzdGVyZWRfQmlvcmV0ZW5fbGluZWQNCm5vcm1hbGl6ZWRfY2x1c3RlclssMjozXSA8LSBzY2FsZShjbHVzdGVyZWRfQmlvcmV0ZW5fbGluZWRbLDI6M10pDQoNCiNFbGJvdyBtZXRob2Qgc2hvd3MgYSBzdWJ0bGUgZWxib3cgYXQgY2x1c3RlciA0LWhlbmNlIDQgY2x1c3RlcnMgaXMgb3B0aW11bQ0KI251bWJlciBvZiBjbHVzdGVycw0KZnZpel9uYmNsdXN0KG5vcm1hbGl6ZWRfY2x1c3RlclssMjozXSwga21lYW5zLCBtZXRob2QgPSAid3NzIikNCg0KI2stbWVhbnMgDQojIENsdXN0ZXIgdXNpbmcga21lYW5zIHdpdGggZml2ZSBjbHVzdGVycw0KY2x1c3Rlcl9zb2x1dGlvbiA8LSBrbWVhbnMobm9ybWFsaXplZF9jbHVzdGVyWywyOjNdLCBjZW50ZXJzID0gMikNCg0KIyBTdG9yZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBiYWNrIGludG8gdGhlIGNsdXN0ZXJpbmcgZGF0YSBmcmFtZSBvYmplY3QNCmNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZCRjbHVzdGVyIDwtZmFjdG9yKGNsdXN0ZXJfc29sdXRpb24kY2x1c3RlcikgDQoNCiMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNsdXN0ZXIgYXNzaWdubWVudHMNCnRhYmxlKGNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZCRjbHVzdGVyKQ0KDQojIEdyb3VwIGJ5IHRoZSBjbHVzdGVyIGFzc2lnbm1lbnQgYW5kIGNhbGN1bGF0ZSBhdmVyYWdlcw0Kc3lzX2NsdXNfYXZnIDwtIGNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZCAlPiUNCiAgICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgICBzdW1tYXJpemVfaWYoaXMubnVtZXJpYywgbWVhbikNCg0KIyBWaWV3IHRoZSByZXN1bHRpbmcgdGFibGUNCmthYmxlKHN5c19jbHVzX2F2ZykNCg0KIzMgRCBwbG90DQpwbG90X2x5KGNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZCwgeCA9IH5zeXNfaW1wZXJ2ZGFfZnQyLCB5ID0gfnN5c19yYXdzdG9ybXNpemVtYW5hZ2VkX2luKSAlPiUNCiAgYWRkX21hcmtlcnMoY29sb3IgPSB+Y2x1c3RlcikNCmBgYA0KDQpCaW9yZXRlbnRpb24gKHVubGluZWQpIGNsdXN0ZXJpbmcuDQoNCmBgYHtyIHNlY3Rpb24gMTQgQmlvcmV0ZW50aW9uIHVubGluZWQgY2x1c3RlcmluZ30NCg0KY2x1c3RlcmVkX0Jpb3JldGVuX3VubGluZWQgPC0gdGFibGVfYWxsICU+JQ0KICBmaWx0ZXIoc3lzX21vZGVsaW5wdXRjYXRlZ29yeSA9PSAiQmlvcmV0ZW50aW9uICh1bmxpbmVkKSIpICU+JQ0KICBzZWxlY3Qoc3lzdGVtX2lkLCBzeXNfaW1wZXJ2ZGFfZnQyLCBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbiwgbG9hZGluZ19yYXRpbywgc3lzX21vZGVsaW5wdXRjYXRlZ29yeSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojbm9ybWFsemUgdXNpbmcgbWVhbi1zZCBzdGFuZGFyZGl6YXRpb24NCm5vcm1hbGl6ZWRfY2x1c3RlciA8LSBjbHVzdGVyZWRfQmlvcmV0ZW5fdW5saW5lZA0Kbm9ybWFsaXplZF9jbHVzdGVyWywyOjRdIDwtIHNjYWxlKGNsdXN0ZXJlZF9CaW9yZXRlbl91bmxpbmVkWywyOjRdKQ0KDQojRWxib3cgbWV0aG9kIHNob3dzIGEgc3VidGxlIGVsYm93IGF0IGNsdXN0ZXIgNC1oZW5jZSA0IGNsdXN0ZXJzIGlzIG9wdGltdW0NCiNudW1iZXIgb2YgY2x1c3RlcnMNCmZ2aXpfbmJjbHVzdChub3JtYWxpemVkX2NsdXN0ZXJbLDI6NF0sIGttZWFucywgbWV0aG9kID0gIndzcyIpDQoNCiNrLW1lYW5zIA0KIyBDbHVzdGVyIHVzaW5nIGttZWFucyB3aXRoIGZpdmUgY2x1c3RlcnMNCmNsdXN0ZXJfc29sdXRpb24gPC0ga21lYW5zKG5vcm1hbGl6ZWRfY2x1c3RlclssMjo0XSwgY2VudGVycyA9IDMpDQoNCiMgU3RvcmUgdGhlIGNsdXN0ZXIgYXNzaWdubWVudHMgYmFjayBpbnRvIHRoZSBjbHVzdGVyaW5nIGRhdGEgZnJhbWUgb2JqZWN0DQpjbHVzdGVyZWRfQmlvcmV0ZW5fdW5saW5lZCRjbHVzdGVyIDwtZmFjdG9yKGNsdXN0ZXJfc29sdXRpb24kY2x1c3RlcikgDQoNCiMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNsdXN0ZXIgYXNzaWdubWVudHMNCnRhYmxlKGNsdXN0ZXJlZF9CaW9yZXRlbl91bmxpbmVkJGNsdXN0ZXIpDQoNCiMgR3JvdXAgYnkgdGhlIGNsdXN0ZXIgYXNzaWdubWVudCBhbmQgY2FsY3VsYXRlIGF2ZXJhZ2VzDQpzeXNfY2x1c19hdmcgPC0gY2x1c3RlcmVkX0Jpb3JldGVuX3VubGluZWQgJT4lDQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogICAgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIG1lYW4pDQoNCiMgVmlldyB0aGUgcmVzdWx0aW5nIHRhYmxlDQprYWJsZShzeXNfY2x1c19hdmcpDQoNCiMzIEQgcGxvdA0KcGxvdF9seShjbHVzdGVyZWRfQmlvcmV0ZW5fdW5saW5lZCwgeCA9IH5zeXNfaW1wZXJ2ZGFfZnQyLCB5ID0gfnN5c19yYXdzdG9ybXNpemVtYW5hZ2VkX2luLCB6PSB+bG9hZGluZ19yYXRpbykgJT4lDQogIGFkZF9tYXJrZXJzKGNvbG9yID0gfmNsdXN0ZXIpDQpgYGANCg0KYGBge3Igc2VjdGlvbiAxNSBTdWJzdXJmYWNlIGluZmlsdHJhdGlvbiBjbHVzdGVyaW5nfQ0KDQpjbHVzdGVyZWRfc3Vic3VyZmFjZSA8LSB0YWJsZV9hbGwgJT4lDQogIGZpbHRlcihzeXNfbW9kZWxpbnB1dGNhdGVnb3J5ID09ICJTdWJzdXJmYWNlIGluZmlsdHJhdGlvbiIpICU+JQ0KICBzZWxlY3Qoc3lzdGVtX2lkLCBzeXNfaW1wZXJ2ZGFfZnQyLCBzeXNfcmF3c3Rvcm1zaXplbWFuYWdlZF9pbiwgbG9hZGluZ19yYXRpbywgc3lzX21vZGVsaW5wdXRjYXRlZ29yeSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojbm9ybWFsemUgdXNpbmcgbWVhbi1zZCBzdGFuZGFyZGl6YXRpb24NCm5vcm1hbGl6ZWRfY2x1c3RlciA8LSBjbHVzdGVyZWRfc3Vic3VyZmFjZQ0Kbm9ybWFsaXplZF9jbHVzdGVyWywyOjRdIDwtIHNjYWxlKGNsdXN0ZXJlZF9zdWJzdXJmYWNlWywyOjRdKQ0KDQojRWxib3cgbWV0aG9kIHNob3dzIGEgc3VidGxlIGVsYm93IGF0IGNsdXN0ZXIgNC1oZW5jZSA0IGNsdXN0ZXJzIGlzIG9wdGltdW0NCiNudW1iZXIgb2YgY2x1c3RlcnMNCmZ2aXpfbmJjbHVzdChub3JtYWxpemVkX2NsdXN0ZXJbLDI6NF0sIGttZWFucywgbWV0aG9kID0gIndzcyIpDQoNCiNrLW1lYW5zIA0KIyBDbHVzdGVyIHVzaW5nIGttZWFucyB3aXRoIGZpdmUgY2x1c3RlcnMNCmNsdXN0ZXJfc29sdXRpb24gPC0ga21lYW5zKG5vcm1hbGl6ZWRfY2x1c3RlclssMjo0XSwgY2VudGVycyA9IDIpDQoNCiMgU3RvcmUgdGhlIGNsdXN0ZXIgYXNzaWdubWVudHMgYmFjayBpbnRvIHRoZSBjbHVzdGVyaW5nIGRhdGEgZnJhbWUgb2JqZWN0DQpjbHVzdGVyZWRfc3Vic3VyZmFjZSRjbHVzdGVyIDwtZmFjdG9yKGNsdXN0ZXJfc29sdXRpb24kY2x1c3RlcikgDQoNCiMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNsdXN0ZXIgYXNzaWdubWVudHMNCnRhYmxlKGNsdXN0ZXJlZF9zdWJzdXJmYWNlJGNsdXN0ZXIpDQoNCiMgR3JvdXAgYnkgdGhlIGNsdXN0ZXIgYXNzaWdubWVudCBhbmQgY2FsY3VsYXRlIGF2ZXJhZ2VzDQpzeXNfY2x1c19hdmcgPC0gY2x1c3RlcmVkX3N1YnN1cmZhY2UgJT4lDQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogICAgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIG1lYW4pDQoNCiMgVmlldyB0aGUgcmVzdWx0aW5nIHRhYmxlDQprYWJsZShzeXNfY2x1c19hdmcpDQoNCiMzIEQgcGxvdA0KcGxvdF9seShjbHVzdGVyZWRfc3Vic3VyZmFjZSwgeCA9IH5zeXNfaW1wZXJ2ZGFfZnQyLCB5ID0gfnN5c19yYXdzdG9ybXNpemVtYW5hZ2VkX2luLCB6PSB+bG9hZGluZ19yYXRpbykgJT4lDQogIGFkZF9tYXJrZXJzKGNvbG9yID0gfmNsdXN0ZXIpDQpgYGANCg0KYGBge3Igc2VjdGlvbiAxNiBTdWJzdXJmYWNlIHNsb3cgcmVsZWFzZSAobGluZWQpCSBjbHVzdGVyaW5nfQ0KDQpjbHVzdGVyZWRfc2xvd3JlbF9saW5lZCA8LSB0YWJsZV9hbGwgJT4lDQogIGZpbHRlcihzeXNfbW9kZWxpbnB1dGNhdGVnb3J5ID09ICJTdWJzdXJmYWNlIHNsb3cgcmVsZWFzZSAobGluZWQpIikgJT4lDQogIHNlbGVjdChzeXN0ZW1faWQsIHN5c19pbXBlcnZkYV9mdDIsIHN5c19yYXdzdG9ybXNpemVtYW5hZ2VkX2luLCBzeXNfbW9kZWxpbnB1dGNhdGVnb3J5KSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBkaXN0aW5jdCgpDQoNCiNub3JtYWx6ZSB1c2luZyBtZWFuLXNkIHN0YW5kYXJkaXphdGlvbg0Kbm9ybWFsaXplZF9jbHVzdGVyIDwtIGNsdXN0ZXJlZF9zbG93cmVsX2xpbmVkDQpub3JtYWxpemVkX2NsdXN0ZXJbLDI6M10gPC0gc2NhbGUoY2x1c3RlcmVkX3Nsb3dyZWxfbGluZWRbLDI6M10pDQoNCiNFbGJvdyBtZXRob2Qgc2hvd3MgYSBzdWJ0bGUgZWxib3cgYXQgY2x1c3RlciA0LWhlbmNlIDQgY2x1c3RlcnMgaXMgb3B0aW11bQ0KI251bWJlciBvZiBjbHVzdGVycw0KZnZpel9uYmNsdXN0KG5vcm1hbGl6ZWRfY2x1c3RlclssMjozXSwga21lYW5zLCBtZXRob2QgPSAid3NzIikNCg0KI2stbWVhbnMgDQojIENsdXN0ZXIgdXNpbmcga21lYW5zIHdpdGggZml2ZSBjbHVzdGVycw0KY2x1c3Rlcl9zb2x1dGlvbiA8LSBrbWVhbnMobm9ybWFsaXplZF9jbHVzdGVyWywyOjNdLCBjZW50ZXJzID0gMikNCg0KIyBTdG9yZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBiYWNrIGludG8gdGhlIGNsdXN0ZXJpbmcgZGF0YSBmcmFtZSBvYmplY3QNCmNsdXN0ZXJlZF9zbG93cmVsX2xpbmVkJGNsdXN0ZXIgPC1mYWN0b3IoY2x1c3Rlcl9zb2x1dGlvbiRjbHVzdGVyKSANCg0KIyBMb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY2x1c3RlciBhc3NpZ25tZW50cw0KdGFibGUoY2x1c3RlcmVkX3Nsb3dyZWxfbGluZWQkY2x1c3RlcikNCg0KIyBHcm91cCBieSB0aGUgY2x1c3RlciBhc3NpZ25tZW50IGFuZCBjYWxjdWxhdGUgYXZlcmFnZXMNCnN5c19jbHVzX2F2ZyA8LSBjbHVzdGVyZWRfc2xvd3JlbF9saW5lZCAlPiUNCiAgICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgICBzdW1tYXJpemVfaWYoaXMubnVtZXJpYywgbWVhbikNCg0KIyBWaWV3IHRoZSByZXN1bHRpbmcgdGFibGUNCmthYmxlKHN5c19jbHVzX2F2ZykNCg0KIzMgRCBwbG90DQpwbG90X2x5KGNsdXN0ZXJlZF9zbG93cmVsX2xpbmVkLCB4ID0gfnN5c19pbXBlcnZkYV9mdDIsIHkgPSB+c3lzX3Jhd3N0b3Jtc2l6ZW1hbmFnZWRfaW4pICU+JQ0KICBhZGRfbWFya2Vycyhjb2xvciA9IH5jbHVzdGVyKQ0KDQoNCmBgYA0KDQpgYGB7ciBzZWN0aW9uIDE3IFN1YnN1cmZhY2Ugc2xvdyByZWxlYXNlICh1bmxpbmVkKQl9DQoNCmNsdXN0ZXJlZF9zbG93cmVsX3VubGluZWQgPC0gdGFibGVfYWxsICU+JQ0KICBmaWx0ZXIoc3lzX21vZGVsaW5wdXRjYXRlZ29yeSA9PSAiU3Vic3VyZmFjZSBzbG93IHJlbGVhc2UgKHVubGluZWQpIikgJT4lDQogIHNlbGVjdChzeXN0ZW1faWQsIHN5c19pbXBlcnZkYV9mdDIsIHN5c19yYXdzdG9ybXNpemVtYW5hZ2VkX2luLCBsb2FkaW5nX3JhdGlvLCBzeXNfbW9kZWxpbnB1dGNhdGVnb3J5KSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBkaXN0aW5jdCgpDQoNCiNub3JtYWx6ZSB1c2luZyBtZWFuLXNkIHN0YW5kYXJkaXphdGlvbg0Kbm9ybWFsaXplZF9jbHVzdGVyIDwtIGNsdXN0ZXJlZF9zbG93cmVsX3VubGluZWQNCm5vcm1hbGl6ZWRfY2x1c3RlclssMjozXSA8LSBzY2FsZShjbHVzdGVyZWRfc2xvd3JlbF91bmxpbmVkWywyOjNdKQ0KDQojRWxib3cgbWV0aG9kIHNob3dzIGEgc3VidGxlIGVsYm93IGF0IGNsdXN0ZXIgNC1oZW5jZSA0IGNsdXN0ZXJzIGlzIG9wdGltdW0NCiNudW1iZXIgb2YgY2x1c3RlcnMNCmZ2aXpfbmJjbHVzdChub3JtYWxpemVkX2NsdXN0ZXJbLDI6M10sIGttZWFucywgbWV0aG9kID0gIndzcyIpDQoNCiNrLW1lYW5zIA0KIyBDbHVzdGVyIHVzaW5nIGttZWFucyB3aXRoIGZpdmUgY2x1c3RlcnMNCmNsdXN0ZXJfc29sdXRpb24gPC0ga21lYW5zKG5vcm1hbGl6ZWRfY2x1c3RlclssMjozXSwgY2VudGVycyA9IDIpDQoNCiMgU3RvcmUgdGhlIGNsdXN0ZXIgYXNzaWdubWVudHMgYmFjayBpbnRvIHRoZSBjbHVzdGVyaW5nIGRhdGEgZnJhbWUgb2JqZWN0DQpjbHVzdGVyZWRfc2xvd3JlbF91bmxpbmVkJGNsdXN0ZXIgPC1mYWN0b3IoY2x1c3Rlcl9zb2x1dGlvbiRjbHVzdGVyKSANCg0KIyBMb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY2x1c3RlciBhc3NpZ25tZW50cw0KdGFibGUoY2x1c3RlcmVkX3Nsb3dyZWxfdW5saW5lZCRjbHVzdGVyKQ0KDQojIEdyb3VwIGJ5IHRoZSBjbHVzdGVyIGFzc2lnbm1lbnQgYW5kIGNhbGN1bGF0ZSBhdmVyYWdlcw0Kc3lzX2NsdXNfYXZnIDwtIGNsdXN0ZXJlZF9zbG93cmVsX3VubGluZWQgJT4lDQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogICAgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIG1lYW4pDQoNCiMgVmlldyB0aGUgcmVzdWx0aW5nIHRhYmxlDQprYWJsZShzeXNfY2x1c19hdmcpDQoNCiMzIEQgcGxvdA0KcGxvdF9seShjbHVzdGVyZWRfc2xvd3JlbF91bmxpbmVkLCB4ID0gfnN5c19pbXBlcnZkYV9mdDIsIHkgPSB+c3lzX3Jhd3N0b3Jtc2l6ZW1hbmFnZWRfaW4sIHogPSB+bG9hZGluZ19yYXRpbykgJT4lDQogIGFkZF9tYXJrZXJzKGNvbG9yID0gfmNsdXN0ZXIpDQpgYGANCg0KVXBvbiBjbHVzdGVyaW5nIHRoZSBzeXN0ZW1zLCB0aGUgZGF0YSB3aWxsIGJlIGNvbGxlY3RlZCBpbiBhIHVuaWZpZWQgZGF0YSBmcmFtZSBmb3Igc3RyYXRpZmllZCBzYW1wbGluZy4gVGhlIHN0cmF0aWZpZWQgc2FtcGxpbmcgY3JlYXRlcyBhIGJhbGFuY2VkIGxpc3Qgb2Ygc3lzdGVtcyB0aGF0IGFyZSByZWZsZWN0aXZlIG9mIHRoZSBzaXplIG9mIGVhY2ggc21wIHR5cGUgYW5kIHRoYXQgb2YgdGhlIGludGVybmFsIGNsdXN0ZXJzLiBGb3IgZXhhbXBsZSwgdGhlIGNvZGUgYmVsb3cgaGFzIGdlbmVyYXRlZCA1OCBzeXN0ZW0gKFx+IDEwJSBvZiB0b3RhbCB1bm1vbml0b3JlZCBzeXN0ZW1zKTsgdGhlIHNpemUgb2YgZWFjaCBzeXN0ZW0gdHlwZSBpcyBwcm9wb3J0aW9uYWwgdG8gdGhhdCBvZiB0aGUgcG9wdWxhdGlvbiwgYW5kIHdpdGhpbiBlYWNoIHR5cGUgb2Ygc3lzdGVtcywgYSBwcm9wb3J0aW9uYWwgbnVtYmVyIG9mIHN5c3RlbXMgaGFzIGJlZW4gY2hvc2VuIGZyb20gZWFjaCBjbHVzdGVyIGUuZy4sIGluIEJpb2luZmlsdHJhdGlvbiB0eXBlIHN5c3RlbXMsIDcgc3lzdGVtcyBhcmUgcmFuZG9tbHkgY2hvc2VuIGZyb20gY2x1c3RlciAzLCAzIHN5c3RlbXMgZnJvbSBjbHVzdGVyIDIsIGFuZCAyIHN5c3RlbXMgZnJvbSBjbHVzdGVyIDEuDQoNCmBgYHtyIHNlY3Rpb24gMTggc2FtcGxpbmd9DQojYmluZGluZyBhbGwgc3ViLXR5cGUgZ3JvdXBzIGludG8gb25lIHRhYmxlDQpzeXNfY2x1c3RlcmVkX2FsbCA8LSBiaW5kX3Jvd3MoY2x1c3RlcmVkX0Jpb2luZmlsdHJhdGlvblssYygic3lzdGVtX2lkIiwiY2x1c3RlciIsInN5c19tb2RlbGlucHV0Y2F0ZWdvcnkiKV0sIGNsdXN0ZXJlZF9CaW9yZXRlbl9saW5lZFssYygic3lzdGVtX2lkIiwiY2x1c3RlciIsInN5c19tb2RlbGlucHV0Y2F0ZWdvcnkiKV0sIGNsdXN0ZXJlZF9CaW9yZXRlbl91bmxpbmVkWyxjKCJzeXN0ZW1faWQiLCJjbHVzdGVyIiwic3lzX21vZGVsaW5wdXRjYXRlZ29yeSIpXSwgY2x1c3RlcmVkX3Nsb3dyZWxfbGluZWRbLGMoInN5c3RlbV9pZCIsImNsdXN0ZXIiLCJzeXNfbW9kZWxpbnB1dGNhdGVnb3J5IildLCBjbHVzdGVyZWRfc2xvd3JlbF91bmxpbmVkWyxjKCJzeXN0ZW1faWQiLCJjbHVzdGVyIiwic3lzX21vZGVsaW5wdXRjYXRlZ29yeSIpXSwgY2x1c3RlcmVkX3N1YnN1cmZhY2VbLGMoInN5c3RlbV9pZCIsImNsdXN0ZXIiLCJzeXNfbW9kZWxpbnB1dGNhdGVnb3J5IildKQ0KDQojc2FtcGxpbmcgY29kZQ0Kc3RyYXRpZmllZF9zYW1wbGUgPC0gc3lzX2NsdXN0ZXJlZF9hbGwgJT4lDQogICAgZ3JvdXBfYnkoc3lzX21vZGVsaW5wdXRjYXRlZ29yeSwgY2x1c3RlcikgJT4lDQogICAgc2FtcGxlX2ZyYWMoc2l6ZT0wLjEpDQoNCmthYmxlKHN0cmF0aWZpZWRfc2FtcGxlKQ0KYGBgDQo=